home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / aztecnos.arc / 8250.C next >
Encoding:
C/C++ Source or Header  |  1989-02-13  |  6.8 KB  |  340 lines

  1. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "iface.h"
  5. #include "asy.h"
  6. #include "8250.h"
  7.  
  8. void (*getirq())();
  9. void asy0vec(),asy1vec(),asy2vec(),asy3vec(),asy4vec();
  10. int kbread();
  11. static int asyrxint(),asytxint();
  12.  
  13. struct asy Asy[ASY_MAX];
  14. unsigned Nasy;
  15. /* ASY interrupt handlers */
  16. void (*Handle[])() = {asy0vec,asy1vec,asy2vec,asy3vec,asy4vec};
  17.  
  18. /* Initialize asynch port "dev" */
  19. int
  20. asy_init(dev,iface,arg1,arg2,bufsize)
  21. int16 dev;
  22. struct iface *iface;
  23. char *arg1,*arg2;    /* Attach args for address and vector */
  24. unsigned bufsize;
  25. {
  26.     register unsigned base;
  27.     register struct fifo *fp;
  28.     register struct asy *ap;
  29.     char i_state;
  30.  
  31.     ap = &Asy[dev];
  32.     ap->iface = iface;
  33.     ap->addr = htoi(arg1);
  34.     ap->vec = htoi(arg2);
  35.     /* Set up receiver FIFO */
  36.     fp = &ap->fifo;
  37.     if((fp->buf = malloc(bufsize)) == NULLCHAR){
  38.         printf("asy%d: No space for rx buffer\r\n",dev);
  39.         return;
  40.     }
  41.     fp->bufsize = bufsize;
  42.     fp->wp = fp->rp = fp->buf;
  43.     fp->cnt = 0;
  44.  
  45.     base = ap->addr;
  46.  
  47.     /* Purge the receive data buffer */
  48.     (void)inportb(base+RBR);
  49.  
  50.     i_state = dirps();
  51.  
  52.     /* Save original interrupt vector, mask state, control bits */
  53.     ap->save.vec = getirq(ap->vec);
  54.     ap->save.mask = getmask(ap->vec);
  55.     ap->save.lcr = inportb(base+LCR);
  56.     ap->save.ier = inportb(base+IER);
  57.     ap->save.mcr = inportb(base+MCR);
  58.  
  59.     /* save speed bytes */
  60.     setbit(base+LCR,LCR_DLAB);
  61.     ap->save.divl = inportb(base+DLL);
  62.     ap->save.divh = inportb(base+DLM);
  63.     clrbit(base+LCR,LCR_DLAB);
  64.  
  65.     /* Set interrupt vector to SIO handler */
  66.     setirq(ap->vec,Handle[dev]);
  67.  
  68.     /* Set line control register: 8 bits, no parity */
  69.     outportb(base+LCR,(char)LCR_8BITS);
  70.  
  71.     /* Turn on receive interrupt enable in 8250, leave transmit
  72.      * and modem status interrupts turned off for now
  73.      */
  74.     outportb(base+IER,(char)IER_DAV);
  75.  
  76.     /* Set modem control register: assert DTR, RTS, turn on 8250
  77.      * master interrupt enable (connected to OUT2)
  78.      */
  79.     outportb(base+MCR,(char)(MCR_DTR|MCR_RTS|MCR_OUT2));
  80.  
  81.     /* Enable interrupt */
  82.     maskon(ap->vec);
  83.     restore(i_state);
  84. }
  85. int
  86. asy_stop(iface)
  87. struct iface *iface;
  88. {
  89.     register unsigned base;
  90.     register struct asy *ap;
  91.     char i_state;
  92.  
  93.     ap = &Asy[iface->dev];
  94.     base = ap->addr;
  95.  
  96.     /* Purge the receive data buffer */
  97.     (void)inportb(base+RBR);
  98.  
  99.     /* Restore original interrupt vector and 8259 mask state */
  100.     i_state = dirps();
  101.     setirq(ap->vec,ap->save.vec);
  102.     if(ap->save.mask)
  103.         maskon(ap->vec);
  104.     else
  105.         maskoff(ap->vec);
  106.  
  107.     /* Restore speed regs */
  108.     setbit(base+LCR,LCR_DLAB);
  109.     outportb(base+DLL,ap->save.divl);    /* Low byte */
  110.     outportb(base+DLM,ap->save.divh);    /* Hi byte */
  111.     clrbit(base+LCR,LCR_DLAB);
  112.  
  113.     /* Restore control regs */
  114.     outportb(base+LCR,ap->save.lcr);
  115.     outportb(base+IER,ap->save.ier);
  116.     outportb(base+MCR,ap->save.mcr);
  117.     restore(i_state);
  118. }
  119. /* Asynchronous line I/O control */
  120. int
  121. asy_ioctl(iface,argc,argv)
  122. struct iface *iface;
  123. int argc;
  124. char *argv[];
  125. {
  126.     if(argc < 1){
  127.         printf("%d\r\n",Asy[iface->dev].speed);
  128.         return 0;
  129.     }
  130.     return asy_speed(iface->dev,atoi(argv[0]));
  131. }
  132. /* Set asynch line speed */
  133. int
  134. asy_speed(dev,speed)
  135. int16 dev;
  136. int speed;
  137. {
  138.     register unsigned base;
  139.     register int divisor;
  140.     char i_state;
  141.  
  142.     if(speed == 0 || dev >= Nasy)
  143.         return -1;
  144.     
  145.     base = Asy[dev].addr;
  146.     Asy[dev].speed = speed;
  147.  
  148.     divisor = BAUDCLK / (long)speed;
  149.  
  150.     i_state = dirps();
  151.  
  152.     /* Purge the receive data buffer */
  153.     (void)inportb(base+RBR);
  154.  
  155.     /* Turn on divisor latch access bit */
  156.     setbit(base+LCR,LCR_DLAB);
  157.  
  158.     /* Load the two bytes of the register */
  159.     outportb(base+DLL,(char)(divisor & 0xff));        /* Low byte */
  160.     outportb(base+DLM,(char)((divisor >> 8) & 0xff));    /* Hi byte */
  161.  
  162.     /* Turn off divisor latch access bit */
  163.     clrbit(base+LCR,LCR_DLAB);
  164.  
  165.     restore(i_state);
  166.     return 0;
  167. }
  168.  
  169. /* Send a buffer to serial transmitter */
  170. void
  171. asy_output(dev,buf,cnt)
  172. unsigned dev;
  173. char *buf;
  174. unsigned short cnt;
  175. {
  176.     register struct dma *dp;
  177.     unsigned base;
  178.     char i_state;
  179.  
  180.     if(dev >= Nasy)
  181.         return;
  182.     base = Asy[dev].addr;
  183.     dp = &Asy[dev].dma;
  184.     i_state = dirps();
  185.     if(dp->flags){
  186.         restore(i_state);
  187.         return;    /* Already busy */
  188.     }
  189.     dp->data = buf;
  190.     dp->cnt = cnt;
  191.     dp->flags = 1;
  192.     /* Enable transmitter buffer empty interrupt and simulate
  193.      * an interrupt; this will get things rolling.
  194.      */
  195.     setbit(base+IER,IER_TxE);
  196.     asytxint(dev);
  197.     restore(i_state);
  198. }
  199. /* Blocking read from asynch line
  200.  * Returns count of characters read
  201.  */
  202. char
  203. get_asy(dev)
  204. int16 dev;
  205. {
  206.     char i_state;
  207.     register struct fifo *fp;
  208.     char c;
  209.  
  210.     fp = &Asy[dev].fifo;
  211.  
  212.     i_state = dirps();
  213.     while(fp->cnt == 0)
  214.         pwait(fp);
  215.     fp->cnt--;
  216.     restore(i_state);
  217.  
  218.     c = *fp->rp++;
  219.     if(fp->rp >= &fp->buf[fp->bufsize])
  220.         fp->rp = fp->buf;
  221.  
  222.     return c;
  223. }
  224. /* Interrupt handler for 8250 asynch chip */
  225. void
  226. asyint(dev)
  227. unsigned dev;
  228. {
  229.     register unsigned base;
  230.     register char iir;
  231.     struct fifo *fp;
  232.     int cnt = 0;
  233.  
  234.     base = Asy[dev].addr;
  235.     fp = &Asy[dev].fifo;
  236.     while(((iir = inportb(base+IIR)) & IIR_IP) == 0){
  237.         switch(iir & IIR_ID){
  238.         case IIR_RDA:    /* Receiver interrupt */
  239.             cnt += asyrxint(dev);
  240.             break;
  241.         case IIR_THRE:    /* Transmit interrupt */
  242.             asytxint(dev);
  243.             break;
  244.         }
  245.     }
  246.     if(cnt != 0)
  247.         psignal(fp,1);
  248. }
  249. /* Process 8250 receiver interrupts */
  250. static int
  251. asyrxint(dev)
  252. unsigned dev;
  253. {
  254.     unsigned base;
  255.     register struct fifo *fp;
  256.     struct asy *asyp;
  257.     char c;
  258.     int cnt = 0;
  259.     char lsr;
  260.  
  261.     asyp = &Asy[dev];
  262.     base = asyp->addr;
  263.     fp = &asyp->fifo;
  264.     for(;;){
  265.         lsr = inportb(base+LSR);
  266.         if(lsr & LSR_OE)
  267.             asyp->overrun++;
  268.  
  269.         if(lsr & LSR_DR){
  270.             asyp->rxchar++;
  271.             c = inportb(base+RBR);
  272.             /* If buffer is full, we have no choice but
  273.              * to drop the character
  274.              */
  275.             if(fp->cnt != fp->bufsize){
  276.                 *fp->wp++ = c;
  277.                 if(fp->wp >= &fp->buf[fp->bufsize])
  278.                     /* Wrap around */
  279.                     fp->wp = fp->buf;
  280.                 fp->cnt++;
  281.                 cnt++;
  282.             }
  283.         } else
  284.             break;
  285.     }
  286.     return cnt;
  287. }
  288. /* Handle 8250 transmitter interrupts */
  289. static
  290. asytxint(dev)
  291. unsigned dev;
  292. {
  293.     register struct dma *dp;
  294.     register unsigned base;
  295.     struct asy *asyp;
  296.  
  297.     asyp = &Asy[dev];
  298.     base = asyp->addr;
  299.     dp = &asyp->dma;
  300.     if(!dp->flags){
  301.         /* "Shouldn't happen", but disable transmit
  302.          * interrupts anyway
  303.          */
  304.         clrbit(base+IER,IER_TxE);
  305.         return;    /* Nothing to send */
  306.     }
  307.     while(inportb(base+LSR) & LSR_THRE){
  308.         asyp->txchar++;
  309.         outportb(base+THR,*dp->data++);
  310.         
  311.         if(--dp->cnt == 0){
  312.             dp->flags = 0;
  313.             /* Disable transmit interrupts */
  314.             clrbit(base+IER,IER_TxE);
  315.             asytxdone(dev);
  316.             break;
  317.         }
  318.     }
  319. }
  320. int
  321. stxrdy(dev)
  322. int16 dev;
  323. {
  324.     return(!Asy[dev].dma.flags);
  325. }
  326. int
  327. doasystat(argc,argv)
  328. int argc;
  329. char *argv[];
  330. {
  331.     register struct asy *asyp;
  332.  
  333.     for(asyp = Asy;asyp < &Asy[Nasy];asyp++){
  334.         printf("%s: rxchar %lu overrun %lu txchar %lu\n",
  335.          asyp->iface->name,asyp->rxchar,asyp->overrun,asyp->txchar);
  336.     }
  337.     return 0;
  338. }
  339.  
  340.